package avicit.bdp.dds.api.utils;

import avicit.bdp.common.service.dto.DataSourceDTO;
import avicit.bdp.common.service.service.DataSourceService;
import avicit.bdp.core.util.json.JSONUtils;
import avicit.bdp.dds.dao.entity.LineageFieldDTO;
import avicit.bdp.dds.dao.entity.LineageTableDTO;
import avicit.bdp.dds.dao.entity.ProcessDefinition;
import avicit.bdp.dds.dispatch.model.ProcessData;
import avicit.bdp.dds.dispatch.model.TaskNode;
import avicit.bdp.dds.dispatch.task.sql.SqlParameters;
import avicit.bdp.lineage.druid.LineageSqlUtils;
import avicit.bdp.lineage.druid.model.FieldLineageModel;
import avicit.bdp.lineage.druid.model.FieldNameModel;
import avicit.bdp.lineage.druid.model.TableLineageModel;
import avicit.bdp.lineage.druid.model.TableNameModel;
import avicit.bdp.lineage.druid.util.LineageContext;
import avicit.platform6.commons.utils.ComUtil;
import com.alibaba.druid.DbType;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * 流程数据表解析
 *
 * @author liyb
 * @date 2024/7/11 15:18
 */
@Component
public class LineageUtils {

    private static final Logger logger = LoggerFactory.getLogger(LineageUtils.class);

    @Autowired
    private DataSourceService dataSourceService;

    /**
     * 血缘关系解析
     * @param processDefinition
     * @return
     */
    public Map<String, Object> lineageAnalyse(ProcessDefinition processDefinition) {
        Map<String, Object> map = new HashMap<>();
        String processDefinitionJson = processDefinition.getProcessDefinitionJson();
        ProcessData processData = JSONUtils.parseObject(processDefinitionJson, ProcessData.class);
        if (processData == null) {
            return map;
        }
        //数据开发
        if (processDefinition.getType() == 6) {
            map = analyseCommonProcessNodeList(processData);
        }

        //设置默认信息
        if(map.get("lineageTableList") != null){
            List<LineageTableDTO> lineageTableList = (List<LineageTableDTO>) map.get("lineageTableList");
            if(CollectionUtils.isNotEmpty(lineageTableList)){
                for (LineageTableDTO lineageTable : lineageTableList) {
                    lineageTable.setId(ComUtil.getId());
                    lineageTable.setProjectId(processDefinition.getProjectId());
                    lineageTable.setProcessDefinitionId(processDefinition.getId());
                }
            }
        }
        if(map.get("lineageFieldList") != null){
            List<LineageFieldDTO> lineageFieldList = (List<LineageFieldDTO>) map.get("lineageFieldList");
            if(CollectionUtils.isNotEmpty(lineageFieldList)){
                for (LineageFieldDTO lineageField : lineageFieldList) {
                    lineageField.setId(ComUtil.getId());
                    lineageField.setProjectId(processDefinition.getProjectId());
                    lineageField.setProcessDefinitionId(processDefinition.getId());
                }
            }
        }
        return map;
    }

    /**
     * 数据开发血缘解析
     * @param processData
     * @return
     */
    private Map<String, Object> analyseCommonProcessNodeList(ProcessData processData) {
        Map<String, Object> map = new HashMap<>();
        List<TaskNode> taskNodes = processData.getTasks();
        List<LineageTableDTO> allLineageTableList = new ArrayList<>();
        List<LineageFieldDTO> allLineageFieldList = new ArrayList<>();
        for (TaskNode taskNode : taskNodes) {
            Map<String, Object> lineageMap = handleCommonNode(taskNode);
            if(lineageMap.get("lineageTableList") != null){
                List<LineageTableDTO> lineageTableList = (List<LineageTableDTO>) lineageMap.get("lineageTableList");
                allLineageTableList.addAll(lineageTableList);
            }
            if(lineageMap.get("lineageFieldList") != null){
                List<LineageFieldDTO> lineageFieldList = (List<LineageFieldDTO>) lineageMap.get("lineageFieldList");
                allLineageFieldList.addAll(lineageFieldList);
            }
        }

        map.put("lineageTableList", allLineageTableList);
        map.put("lineageFieldList", allLineageFieldList);
        return map;
    }

    private Map<String, Object> handleCommonNode(TaskNode taskNode) {
        Map<String, Object> map = new HashMap<>();

        if (taskNode.getType().equals("SQL")) {
            //处理SQL节点
            String params = taskNode.getParams();
            SqlParameters p = JSONUtils.parseObject(params, SqlParameters.class);
            if (StringUtils.isBlank(p.getDatasource())) {
                return map;
            }
            String sql = p.getSql();
            List<String> sqlList = new ArrayList<>();
            sqlList.addAll(p.getPreStatements());
            sqlList.add(sql);
            sqlList.addAll(p.getPostStatements());
            map = handleSQLNode(sqlList, p.getDatasource());
        }
        return map;
    }

    /**
     * 解析SQL节点血缘
     * @param sqlList
     * @param datasourceId
     * @return
     */
    private Map<String, Object> handleSQLNode(List<String> sqlList, String datasourceId) {
        Map<String, Object> map = new HashMap<>();
        List<LineageTableDTO> lineageTableList = new ArrayList<>();
        List<LineageFieldDTO> lineageFieldList = new ArrayList<>();
        List<String> sqlList_ = new ArrayList<>();
        if(CollectionUtils.isNotEmpty(sqlList)){
            for (String sql : sqlList) {
                if (StringUtils.isNotEmpty(sql)) {
                    sqlList_.add(sql);
                }
            }
        }
        if(CollectionUtils.isEmpty(sqlList_)){
            return map;
        }

        DataSourceDTO dataSourceDTO = dataSourceService.selectByPrimaryKey(datasourceId);
        String datasourceType = dataSourceDTO.getDatasourceType();
        DbType dbType = DbType.other;
        if (StringUtils.isNotBlank(datasourceType)) {
            dbType = DbType.valueOf(datasourceType.toLowerCase());
        }

        LineageContext context = LineageSqlUtils.getInstance().handle(sqlList_, dbType.name());
        List<TableLineageModel> tableNodeList = context.getTableNodeList();
        for (TableLineageModel model : tableNodeList) {
            TableNameModel targetTable = model.getTargetTable();
            HashSet<TableNameModel> sourceTables = model.getSourceTables();
            for (TableNameModel sourceTable : sourceTables) {
                LineageTableDTO lineageTableDTO = new LineageTableDTO();
                lineageTableDTO.setSourceDatasourceId(datasourceId);
                lineageTableDTO.setSourceTableCode(sourceTable.getTableName());
                lineageTableDTO.setTargetDatasourceId(datasourceId);
                lineageTableDTO.setTargetTableCode(targetTable.getTableName());
                lineageTableDTO.setStatus(1);
                lineageTableList.add(lineageTableDTO);
            }
        }

        List<FieldLineageModel> fieldNodeList = context.getFieldNodeList();
        for (FieldLineageModel model : fieldNodeList) {
            FieldNameModel targetField = model.getTargetField();
            HashSet<FieldNameModel> sourceFields = model.getSourceFields();
            for (FieldNameModel sourceField : sourceFields) {
                LineageFieldDTO lineageFieldDTO = new LineageFieldDTO();
                lineageFieldDTO.setSourceDatasourceId(datasourceId);
                lineageFieldDTO.setSourceTableCode(sourceField.getTableName());
                lineageFieldDTO.setSourceFieldCode(sourceField.getFieldName());
                lineageFieldDTO.setTargetDatasourceId(datasourceId);
                lineageFieldDTO.setTargetTableCode(targetField.getTableName());
                lineageFieldDTO.setTargetFieldCode(targetField.getFieldName());
                lineageFieldDTO.setStatus(1);
                lineageFieldList.add(lineageFieldDTO);
            }
        }
        map.put("lineageTableList", lineageTableList);
        map.put("lineageFieldList", lineageFieldList);
        return map;
    }

}
